home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Leisure Game Pak
/
Leisure Game Pak.iso
/
lpgame1
/
04
/
source
/
mynesgam.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1994-08-17
|
20KB
|
522 lines
(* ..................................................................... *)
(* : file : MYNESGAM.PAS : *)
(* : contents : the game routines for MYNES! : *)
(* : last update : 06-JUL-93 : *)
(* :...................:...............................................: *)
(*
- reveal_tile, mark_tile
- get_computer_move, get_mouse_button
get_field_action, get_control_action, play_game
*)
(* reveal_tile uncovers the tile in col, row unless it is already uncovered
(it is called by uncover_hidden_0s with a pos that is already uncovered)*)
PROCEDURE reveal_tile(VAR scene : SCENE_TYPE;
col, row : COL_ROW_TYPE);
(* uncover_hidden0 reveales a contiguous area of hidden0's *)
(* USES: get_tile_pos(5), reveal_tile(3), SetFillStyle(2), Bar(4),
MouseUpdate(4), ShowMouse() *)
PROCEDURE uncover_hidden0s(VAR scene : SCENE_TYPE;
col, row : COL_ROW_TYPE);
VAR x, y : WORD;
BEGIN
IF (LookIsPL) THEN
BEGIN
(* draw it just like the other visible tiles *)
draw_tile(scene, play_tile, col, row, VISIBLE0);
(* 1.3.93 don't reveal 8 directions in PL-look ... it's not fair *)
{
reveal_tile(scene, real_col(scene, PRED(col)), real_row(scene, PRED(row))); (* NWest *)
reveal_tile(scene, real_col(scene, SUCC(col)), real_row(scene, PRED(row))); (* NEast *)
reveal_tile(scene, real_col(scene, PRED(col)), real_row(scene, SUCC(row))); (* SWest *)
reveal_tile(scene, real_col(scene, SUCC(col)), real_row(scene, SUCC(row))); (* SEast *)
}
END
ELSE
BEGIN (* for MP-look: draw a black box *)
get_tile_pos(scene, col, row, x, y);
SetFillStyle(SOLIDFILL, BLACK);
Bar(x + 2, y + 2,
x + scene.Size.x - 3, y + scene.Size.y - 3);
END;
(* continue reveal_tile in all 4 (not 8) directions
use real cols/rows to make reveal continue its work on the other
side of the playfield as it reaches an edge *)
reveal_tile(scene, real_col(scene, PRED(col)), row); (* West *)
reveal_tile(scene, real_col(scene, SUCC(col)), row); (* East *)
reveal_tile(scene, col, real_row(scene, PRED(row))); (* North *)
reveal_tile(scene, col, real_row(scene, SUCC(row))); (* South *)
END; (* uncover_hidden0s *)
CONST BADMARK = 2; (* points lost when removing a mark *)
VAR contents : CONTENTS_TYPE;
but : BYTE;
BEGIN (* reveal_tile *)
contents := playfield[row, col];
IF (contents IN HIDDEN + MARKED) THEN
BEGIN
HideMouse;
(* LeastCol/Row is the first col/row that has to be examined ...
you needn't examine positions that cannot have changed *)
IF (col < LeastCol) THEN
LeastCol := max(0, PRED(col));
IF (contents in HIDDEN) THEN
BEGIN
(* count the tiles to check for 'WON' *)
IF (Tiles_left > 0) THEN
DEC(Tiles_left);
refresh_bar(DONE_BAR, Tiles_left, TilesToReveal);
DEC(playfield[row, col], ORD(hidden0) - ORD(visible0));
IF (contents = hidden0) THEN
uncover_hidden0s(scene, col, row)
ELSE BEGIN
draw_tile(scene, play_tile, col, row, playfield[row, col]);
IF (contents = hidden_mine) THEN
BEGIN
(* show some flashes *)
GameStatus := BLASTED;
MyDelay(1000);
explode(scene, col, row);
END (* IF *)
ELSE
INC (Score, ORD(contents) - ORD(hidden0));
END; (* ELSE *)
ShowMouse;
END (* IF (contents... *)
ELSE IF (contents IN MARKED) THEN
BEGIN
(* retract this mark and show a hidden tile *)
DEC(MarkedTiles);
IF (Score > BADMARK) THEN
DEC(Score, BADMARK)
ELSE
Score := 0;
DEC(playfield[row, col], ORD(marked0) - ORD(hidden0));
draw_tile(scene, play_tile, col, row, hidden0);
ShowMouse;
(* wait until left mouse button released *)
but := WaitMouseButtons(TRUE, FALSE, FALSE, FALSE);
END; (* ELSE IF *)
END; (* IF *)
END; (* reveal_tile *)
(* mark a tile *)
PROCEDURE mark_tile(VAR scene : SCENE_TYPE;
col, row : COL_ROW_TYPE);
BEGIN
(* LeastCol/Row is the first col/row that has to be examined ...
you needn't examine positions that cannot have changed *)
IF (col < LeastCol) THEN
LeastCol := max(0, PRED(col));
INC(MarkedTiles);
DEC(playfield[row, col], ORD(hidden0) - ORD(marked0));
(* all markers look alike -> show marked0 *)
HideMouse;
draw_tile(scene, play_tile, col, row, marked0);
ShowMouse;
END; (* mark_tile *)
(* produce a clicking noise simulating a mousebutton *)
PROCEDURE computerclick(high : BOOLEAN);
BEGIN
IF (SoundIsON) THEN
BEGIN
IF high THEN
Sound(5600)
ELSE
Sound(5200);
Delay(1); NoSound;
END;
END; (* computerclick *)
FUNCTION get_computer_move(VAR scene : SCENE_TYPE;
VAR mx, my: WORD) : WORD;
TYPE COORDS_LIST_TYPE = ARRAY [1..8] OF COORDS_TYPE;
CONST to_reveal_list : COORDS_LIST_TYPE =
((x:0;y:0),(x:0;y:0),(x:0;y:0),(x:0;y:0),
(x:0;y:0),(x:0;y:0),(x:0;y:0),(x:0;y:0));
to_mark_list : COORDS_LIST_TYPE =
((x:0;y:0),(x:0;y:0),(x:0;y:0),(x:0;y:0),
(x:0;y:0),(x:0;y:0),(x:0;y:0),(x:0;y:0));
to_reveal : BYTE = 0;
to_mark : BYTE = 0;
VAR col, colj,
row, rowi,
randcol, randrow: COL_ROW_TYPE;
marked_list,
hidden_list : COORDS_LIST_TYPE;
no_tiles : BOOLEAN;
contents : CONTENTS_TYPE;
value,
hiddens,
markeds : BYTE;
mdx, mdy : INTEGER;
wait : WORD;
reveal_sound : BOOLEAN;
PROCEDURE count_hidden_marked (col, row : COL_ROW_TYPE);
VAR r_row, r_col,
rowi, colj : COL_ROW_TYPE;
n_cont : CONTENTS_TYPE;
BEGIN
hiddens := 0;
markeds := 0;
(* columns as outer loop to keep same columns together an save mousemoves *)
FOR colj := PRED(col) TO SUCC(col) DO
BEGIN
r_col := real_col(scene, colj);
FOR rowi := PRED(row) TO SUCC(row) DO
BEGIN
r_row := real_row(scene, rowi);
n_cont := playfield[r_row, r_col];
IF (n_cont IN HIDDEN) THEN
BEGIN
INC(hiddens);
hidden_list[hiddens].x := r_col;
hidden_list[hiddens].y := r_row;
END (* IF *)
ELSE IF (n_cont IN MARKED) THEN
BEGIN
INC(markeds);
marked_list[markeds].x := r_col;
marked_list[markeds].y := r_row;
END; (* IF *)
END; (* FOR rowi *)
END; (* FOR colj *)
END; (* count_hidden_marked *)
BEGIN (* get_computer_move *)
IF (GameStatus = DEMO_START) THEN
BEGIN
to_reveal := 0;
to_mark := 0;
GameStatus := DEMO; (* the next move will be normal *)
END; (* IF *)
no_tiles := (to_reveal + to_mark = 0);
(* compute waitstates depending on Speed and Level *)
wait := SPEED_FACTOR[Speed] * 5;
IF (no_tiles) THEN wait := Random(wait * 6) + wait
ELSE wait := Random(wait) + wait DIV 2;
(* the outer loop is on cols to limit mouse movement *)
colj := LeastCol;
WHILE (no_tiles) AND (colj < scene.NumCols) DO
BEGIN
rowi := 0;
WHILE (no_tiles) AND (rowi < scene.NumRows) DO
BEGIN
contents := playfield[rowi, colj];
IF (contents IN VISIBLE) THEN
BEGIN
value := ORD(contents) - ORD(visible0);
count_hidden_marked(colj, rowi);
IF (value = markeds + hiddens) AND (hiddens > 0) THEN
BEGIN
to_mark_list := hidden_list;
to_mark := hiddens;
no_tiles := FALSE;
END (* IF *)
ELSE IF (value = markeds) AND (hiddens > 0) THEN
BEGIN
to_reveal_list := hidden_list;
to_reveal := hiddens;
no_tiles := FALSE;
END (* ELSE IF *)
ELSE IF (value < markeds) THEN
BEGIN
to_reveal_list := marked_list;
to_reveal := markeds;
no_tiles := FALSE;
END (* ELSE IF *)
END; (* IF contents *)
INC(rowi);
END; (* WHILE colj *)
(* all cols before colj were without a result *)
LeastCol := colj;
INC(colj);
END; (* WHILE rowi *)
randrow := Random(scene.NumRows);
randcol := Random(scene.NumCols);
rowi := 0;
IF (no_tiles) THEN INC(wait, 300); (* some more uncertainty *)
(* search for a random hidden tile to be revealed, or if no hidden
can be found, simply reveal a random marked tile *)
WHILE (no_tiles) AND (rowi < scene.NumRows) DO
BEGIN
row := (randrow + rowi) MOD scene.NumRows;
colj := 0;
WHILE (no_tiles) AND (colj < scene.NumCols) DO
BEGIN
col := (randcol + colj) MOD scene.NumCols;
contents := playfield[row, col];
IF (contents IN HIDDEN) THEN
BEGIN
to_reveal := 1;
to_reveal_list[1].x := col;
to_reveal_list[1].y := row;
no_tiles := FALSE;
END (* IF *)
ELSE IF (contents IN MARKED) THEN
BEGIN
to_reveal := 1;
to_reveal_list[1].x := col;
to_reveal_list[1].y := row;
END; (* ELSE IF *)
INC(colj);
END; (* WHILE colj *)
INC(rowi);
END; (* WHILE rowi *)
(* as we reach this point, we know that there is something
to_reveal and/or to_mark, first we do the reveals then the marks *)
IF (to_reveal > 0) THEN
BEGIN
get_computer_move := LEFTMOUSEBUTTON;
col := to_reveal_list[to_reveal].x; (* col *)
row := to_reveal_list[to_reveal].y; (* row *)
DEC(to_reveal);
reveal_sound := TRUE;
END
ELSE IF (to_mark > 0) THEN
BEGIN
get_computer_move := RIGHTMOUSEBUTTON;
col := to_mark_list[to_mark].x; (* col *)
row := to_mark_list[to_mark].y; (* row *)
DEC(to_mark);
reveal_sound := FALSE;
END;
(* search is over ... if tile isn't revealed yet, then ...
let's hesitate for some millisecs
note: if a tile in to_reveal_list is revealed by uncover_hidden0s
it stays in to_reveal_list even though it is visible *)
IF (playfield [row, col] IN HIDDEN + MARKED) THEN
BEGIN
MouseMove(mdx, mdy); (* watch mouse ... *)
IF (ABS(mdx) + ABS(mdy) <= 60) THEN
BEGIN
IF Speed < LASTSPEED THEN MyDelay(wait);
MouseMove(mdx, mdy);
END; (* IF *)
(* drag mouse to the middle of this tile *)
get_tile_middle(scene, col, row, mx, my);
IF (ABS(mdx) + ABS(mdy) > 60) OR
NOT(DragMouse(mx, my, SOFT_DRAG)) THEN
BEGIN (* cancel demo mode *)
GameStatus := PLAY;
(* computer presses no button *)
get_computer_move := 0;
GAME_PAUSE_GADGET.show;
GAME_QUIT_GADGET.show;
GAME_DEMO_GADGET.show;
END (* IF ABS *)
ELSE
BEGIN
MyDelay(2 * SPEED_FACTOR[Speed]);
computerclick(reveal_sound);
END;
END; (* IF playfield *)
END; (* get_computer_move *)
(* get_mouse_button returns as Time_left seconds have passed, or
as one of the mousebuttons is pressed
the time remaining *)
FUNCTION get_mouse_button (VAR scene : SCENE_TYPE;
VAR mx, my, mbut : WORD) : INTEGER;
CONST last_time : WORD = 0;
VAR Time_left : INTEGER;
BEGIN (* get_mouse_button *)
REPEAT
Time_left := PLAYTIMER.read;
IF ESC_pressed THEN
BEGIN
GameStatus := QUIT; (* exit this function/game *)
mbut := NO_MOUSEBUTTON; (* no button pressed *)
END (* IF *)
ELSE
BEGIN
IF (GameStatus IN [PLAY, DEMO, DEMO_START]) THEN
BEGIN
IF (last_time > Time_left) THEN
refresh_bar(TIME_BAR, Time_left, scene.TimeLimit);
last_time := Time_left;
END; (* IF *)
IF (GameStatus IN [DEMO, DEMO_START]) THEN
mbut := get_computer_move(scene, mx, my)
ELSE
mbut := GetMousePos(mx, my);
END; (* ELSE *)
UNTIL (Time_left <= 0) OR
(mbut = LEFTMOUSEBUTTON) OR
(mbut = RIGHTMOUSEBUTTON) OR
(GameStatus = QUIT);
get_mouse_button := Time_left;
END; (* get_mouse_button *)
(* get_field_action returns TRUE if mousebutton is pressed on-field else FALSE
GameStatus must be the actual status (i.e. PLAY or DEMO)
on its return GameStatus contains the new status (PLAY, DEMO, BLASTED) *)
FUNCTION get_field_action(scene : SCENE_TYPE;
mx, my, mbut : INTEGER) : BOOLEAN;
VAR contents : CONTENTS_TYPE;
col, row : COL_ROW_TYPE;
original_time : LONGINT;
BEGIN
DEC(mx, scene.Origin.x); (* that's why mx,my are INTEGERs *)
DEC(my, scene.Origin.y); (* without this they should be WORDs *)
col := mx DIV SUCC(scene.Size.x);
row := my DIV SUCC(scene.Size.y);
IF (in_rect(col, row, 0, 0, scene.NumCols, scene.NumRows)) THEN
BEGIN
get_field_action := TRUE; (* mouse is on field *)
IF (mx MOD SUCC(scene.Size.x) < scene.Size.x) AND
(my MOD SUCC(scene.Size.y) < scene.Size.y) THEN
BEGIN
contents := playfield[row,col];
IF (mbut = LEFTMOUSEBUTTON) AND (contents IN HIDDEN + MARKED) THEN
BEGIN
(* if someone reveals a tile then he plays ...
check GameStatus first, as it may be changed
by reveal_tile (BLASTED, WON) *)
IF (GameStatus = PLAY) THEN
ManPlayed := TRUE
ELSE
ComputerPlayed := TRUE;
reveal_tile(scene, col, row);
END
ELSE IF (mbut = RIGHTMOUSEBUTTON) AND (contents IN HIDDEN) THEN
mark_tile(scene, col, row);
{ ELSE flash; (* illegal input *) }
(* test for WON, all three conditions are necessary *)
IF (Tiles_left = 0) AND
(MarkedTiles = scene.NumMines) AND
(GameStatus <> BLASTED) THEN
BEGIN
GameStatus := WON;
(* increase score because of WON *)
(* Score += 2 * (OriginalTimeLimit - TimeUsed) *)
(* note: we take PRED(...) to give the faster
speeds a slight advantage *)
original_time := scene.TimeLimit * 60 DIV PRED(SPEED_FACTOR[Speed]);
INC(Score, 2*(original_time - (scene.TimeLimit - PLAYTIMER.read)));
END; (* IF *)
END; (* IF *)
END (* IF *)
ELSE get_field_action := FALSE;
END; (* get_field_action *)
PROCEDURE get_control_action;
VAR but : BYTE;
dmx, dmy : INTEGER; (* to reset mousemoves *)
BEGIN
IF (GAME_QUIT_GADGET.handle_mouse_click) THEN
GameStatus := QUIT
ELSE IF (GAME_PAUSE_GADGET.handle_mouse_click) THEN
BEGIN
(* reduce brightness, to prevent player from looking *)
dim_palette(20, SLOW_DIM);
PLAYTIMER.stop;
(* press either button to continue *)
but := WaitMouseButtons(FALSE, TRUE, TRUE, FALSE);
PLAYTIMER.restart;
dim_palette(100, SLOW_DIM);
END (* ELSE IF *)
ELSE IF (GAME_DEMO_GADGET.handle_mouse_click) THEN
BEGIN
GameStatus := DEMO_START; (* 1st move ! *)
GAME_PAUSE_GADGET.hide;
GAME_QUIT_GADGET.hide;
GAME_DEMO_GADGET.hide;
MouseMove(dmx, dmy); (* reset movecounter *)
END; (* ELSE IF *)
END; (* get_control_action *)
(* this is the main playing loop *)
PROCEDURE play_game(scene : SCENE_TYPE);
VAR mrow, mcol : COL_ROW_TYPE;
mx, my, mbut : WORD;
dummy : INTEGER; (* for MouseMove *)
BEGIN
MarkedTiles := 0; (* initialize counters *)
TilesToReveal := scene.NumRows * scene.NumCols - scene.NumMines;
Tiles_left := TilesToReveal;
LeastCol := 0;
Score := 0;
(* noone made a move so far ... *)
ComputerPlayed := FALSE;
ManPlayed := FALSE;
(* get a safe starting point ... *)
REPEAT
mcol := Random(scene.NumCols);
mrow := Random(scene.NumRows);
UNTIL (playfield[mrow, mcol] <> hidden_mine);
(* place mouse in the middle of this tile *)
get_tile_middle(scene, mcol, mrow, mx, my);
SetMousePos(mx, my);
MouseMove(dummy, dummy); (* reset mousemoves *)
(* start timer with TimeLimit seconds left *)
PLAYTIMER.init(scene.TimeLimit);
(* if DEMO then reveal this (safe) tile *)
IF (GameStatus = DEMO_START) THEN
BEGIN
MyDelay(500);
computerclick(true); (* some mouseclick-sound *)
reveal_tile(scene, mcol, mrow);
END; (* IF *)
REPEAT
IF (get_mouse_button(scene, mx, my, mbut) <= 0) THEN
GameStatus := TIMEOUT
ELSE
IF NOT(get_field_action(scene, mx, my, mbut)) THEN
get_control_action;
UNTIL GameStatus IN [BLASTED, QUIT, TIMEOUT, WON];
END; (* play_game *)